#include <opencv2/opencv.hpp> 
#include <mat.h>
#include <vector>
#include <sys/time.h>
#include <iostream>

using namespace std;

double get_current_time()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);

    return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
}

static void opencv_rotate(const cv::Mat& src, cv::Mat& dst, const cv::Mat& tm)
{
    cv::warpAffine(src, dst, tm, src.size(), cv::INTER_LINEAR | cv::WARP_INVERSE_MAP);
}

static void ncnn_rotate(const cv::Mat& src, cv::Mat& dst, const float* tm)
{
    const int w = src.cols;
    const int h = src.rows;
    const int c = src.channels();

    dst.create(h, w, src.type());

    if (c == 1) ncnn::warpaffine_bilinear_c1(src.data, w, h, dst.data, w, h, tm);
    if (c == 2) ncnn::warpaffine_bilinear_c2(src.data, w, h, dst.data, w, h, tm);
    if (c == 3) ncnn::warpaffine_bilinear_c3(src.data, w, h, dst.data, w, h, tm);
    if (c == 4) ncnn::warpaffine_bilinear_c4(src.data, w, h, dst.data, w, h, tm);
}

int main(void){
    cv::Mat src = cv::Mat::ones(1080, 720, CV_8UC3);
    float dx = src.cols / 2;
    float dy = src.rows / 2;
    cv::Point2f center(dx, dy);
    cv::Mat dst1;
    cv::Mat dst2;
    
    const int loop_cnt = 50;
    
    vector<vector<float>> testCase = {{20, 0.2},
                                      {40, 0.4},
                                      {60, 0.6},
                                      {80, 0.8},
                                      {100, 1.0},
                                      {120, 1.25},
                                      {140, 1.6},
                                      {160, 2.5},
                                      {180, 5.0}
    };
    
    float* tmNcnn = new float[6];
    
    std::cout << "index  " << "max  " << "min  " << "avg  "<< std::endl;                                 
    for(int i = 0; i < 9; ++i){
        
        std::cout << i << ":" << std::endl;
        
        {
            double time_min = DBL_MAX;
            double time_max = -DBL_MAX;
            double time_avg = 0;
            cv::Mat roatMat =  cv::getRotationMatrix2D(center, testCase[i][0], testCase[i][1]);
            for(int j = 0; j < loop_cnt; ++j){
                double start = get_current_time();
                opencv_rotate(src, dst1, roatMat); 
                double end = get_current_time();
                double time = end - start;
                time_min = std::min(time_min, time);
                time_max = std::max(time_max, time);
                time_avg += time;
            }
            time_avg /= loop_cnt;
            std ::cout << "  " << time_max << " " << time_min << " " << time_avg << std::endl;
        }

        {
            double time_min = DBL_MAX;
            double time_max = -DBL_MAX;
            double time_avg = 0;
            ncnn::get_rotation_matrix(testCase[i][0], testCase[i][1], dx, dy, tmNcnn);
            
            for(int j = 0; j < loop_cnt; ++j){
                double start = get_current_time();
                ncnn_rotate(src, dst2, tmNcnn);
                double end = get_current_time();
                double time = end - start;
                time_min = std::min(time_min, time);
                time_max = std::max(time_max, time);
                time_avg += time;
            }
            time_avg /= loop_cnt;
            std ::cout << "  " << time_max << " " << time_min << " " << time_avg << std::endl;
        }
        
    }
    
    delete[] tmNcnn;
    return 0;
}
